﻿using System;
using System.ComponentModel.Composition;
using System.IO;
using System.Text;
using SS.Net.AppGen.Models;
using SS.Common.DBBuilder.DBDataStructure;
using SS.Common.Logging;
using SS.Net.AppGen.Utils;

namespace SS.Net.AppGen.WebGenerators.WebViewGenerator
{
    /// <summary>
    /// The algorithm to generate the list view items for common table
    /// </summary>
    [Export(typeof(ListViewItemByCommonAlgorithm))]
    [PartCreationPolicy(CreationPolicy.NonShared)]
    public class ListViewItemByCommonAlgorithm : BaseListViewItemAlgorithm
    {
        /// <summary>
        /// The logger instance
        /// </summary>
        private readonly ILogger Logger = LoggerManager.GetLogger(typeof(ListViewItemByCommonAlgorithm).Name);

        /// <summary>
        /// The default constructor
        /// </summary>
        public ListViewItemByCommonAlgorithm()
        {
            this.XMLTemplate = "PartialListViewItemByCommon.xml";
            this.DeserializeTemplate();
        }

        /// <summary>
        /// Generate the contents of list view items
        /// </summary>
        /// <param name="tbl"></param>
        public override void GenerateContents(Table tbl)
        {
            this.Logger.InfoFormat("Generate ListView[{0}] --> Start", tbl.Name);

            try
            {
                var contents = new StringBuilder(BaseConsts.MAX_BYTES);
                var htmlContents = this.ViewComponents.HtmlContent.Replace(BaseConsts.ConstTable, tbl.Name)
                    .Replace(BaseConsts.ConstGlobalNameSpace, WebConfiguration.Instance.NameSpace)
                    .Replace(BaseConsts.ConstPrimaryKey, tbl.GetPrimaryKey().Name)
                    .Replace(BaseConsts.ConstPluralizeTable, tbl.Name.Pluralize())
                    .Replace(AbstractBaseConsts.ConstTableHeaders, this.BuildTableHeaders(tbl))
                    .Replace(AbstractBaseConsts.ConstTableFields, this.BuildTableFields(tbl))
                    .Replace(AbstractBaseConsts.ConstReferToEditAction, this.BuildReferToEditAction(tbl))
                    .Replace(AbstractBaseConsts.ConstReferToDeleteAction, this.BuildReferToDeleteAction(tbl))
                    .Replace(AbstractBaseConsts.ConstReferToSelectAction, this.BuildReferToSelectAction(tbl));

                contents.AppendLine(htmlContents);

                // Init path
                this.DirPath = Path.Combine(this.GetAppPath(), "WebGenerator", "Views", tbl.Name + "Manager");
                this.InitializeDir(this.DirPath, false);
                // Save contents to a file
                this.SaveFile(contents.ToString().TrimStart(), "_PartialList.cshtml");
            }
            catch (Exception ex)
            {
                this.Logger.ErrorFormat("GenerateContents Error: {0}", ex.ToString());
                throw new Exception(ex.ToString());
            }

            this.Logger.InfoFormat("Generate ListView[{0}] <-- End", tbl.Name);
        }

        /// <summary>
        /// Generate the header fields of table
        /// </summary>
        /// <param name="tbl"></param>
        /// <returns></returns>
        private string BuildTableHeaders(Table tbl)
        {
            var contents = new StringBuilder(BaseConsts.MAX_BYTES);
            var firstAtt = true;

            foreach (var attr in tbl.Attributes)
            {
                if (!attr.IsPrimaryKey)
                {
                    if (firstAtt)
                    {
                        firstAtt = false;
                        contents.AppendLine("<th class=\"table-header-repeat line-left\">");
                    }
                    else
                    {
                        contents.Append(BaseConsts.TAB3).AppendLine("<th class=\"table-header-repeat line-left\">");
                    }
                    contents.Append(BaseConsts.TAB4).AppendLine(string.Format("<a href=\"#\">{0}</a>", attr.Name));
                    contents.Append(BaseConsts.TAB3).AppendLine("</th>");
                }
            }

            return contents.ToString();
        }

        /// <summary>
        /// Generate the fields of table
        /// </summary>
        /// <param name="tbl"></param>
        /// <returns></returns>
        private string BuildTableFields(Table tbl)
        {
            var contents = new StringBuilder(BaseConsts.MAX_BYTES);
            var firstAtt = true;

            foreach (var attr in tbl.Attributes)
            {
                if (!attr.IsPrimaryKey)
                {
                    if (firstAtt)
                    {
                        firstAtt = false;
                        contents.AppendLine("<td>");
                    }
                    else
                    {
                        contents.Append(BaseConsts.TAB3).AppendLine("<td>");
                    }
                    contents.Append(BaseConsts.TAB4).AppendLine(string.Format("@item.{0}", attr.Name));
                    contents.Append(BaseConsts.TAB3).AppendLine("</td>");
                }
            }

            return contents.ToString();
        }

        /// <summary>
        /// Generate the reference to Edit action
        /// </summary>
        /// <param name="tbl"></param>
        /// <returns></returns>
        private string BuildReferToEditAction(Table tbl)
        {
            var contents = new StringBuilder(BaseConsts.MAX_BYTES);
            var pk = tbl.GetPrimaryKey();
            string mainFK;

            contents.Append(tbl.IsTableWithMainForeignKey(out mainFK)
                                ? string.Format(
                                    "<a class=\"icon-1 info-tooltip\" title=\"Edit\" onclick=\"handleEdit{0}(@item.{1}, @item.{2})\"/>",
                                    tbl.Name, pk.Name, mainFK)
                                : string.Format(
                                    "<a class=\"icon-1 info-tooltip\" title=\"Edit\" onclick=\"handleEdit{0}(@item.{1})\"/>",
                                    tbl.Name, pk.Name));

            return contents.ToString();
        }

        /// <summary>
        /// Generate the reference to Delete action
        /// </summary>
        /// <param name="tbl"></param>
        /// <returns></returns>
        private string BuildReferToDeleteAction(Table tbl)
        {
            var contents = new StringBuilder(BaseConsts.MAX_BYTES);
            var pk = tbl.GetPrimaryKey();

            contents.Append(tbl.IsTableWithAjax()
                                ? string.Format(
                                    "<a class=\"icon-2 info-tooltip\" title=\"Delete\" onclick=\"handleDelete{0}(@item.{1})\"/>",
                                    tbl.Name, pk.Name, pk.Name, tbl.Name)
                                : string.Format(
                                    "@Html.ActionLink(\" \", \"Delete{0}WithoutAjax\", new {{ {1} = item.{2}, CurrentPage = ViewBag.CurrentPage }}, new {{ @class = \"icon-2 info-tooltip\", @title = \"Delete\", onclick = \"return confirm('Are you sure you want to Delete it? This action cannot be undone.');\" }})",
                                    tbl.Name, pk.Name, pk.Name));

            return contents.ToString();
        }

        /// <summary>
        /// Generate the reference to Select action
        /// </summary>
        /// <param name="tbl"></param>
        /// <returns></returns>
        private string BuildReferToSelectAction(Table tbl)
        {
            var contents = new StringBuilder(BaseConsts.MAX_BYTES);
            var pk = tbl.GetPrimaryKey();
            string mainFK;

            if (tbl.IsTableWithMainForeignKey(out mainFK))
            {
                var fk = tbl.GetAttribute(mainFK);
                var referTbl = tbl.DataBase.GetTable(fk.ReferTo);
                contents.Append(string.Format("@Html.ActionLink(\" \", \"Select{0}By{1}\", new {{ {2} = Model.{3}[0].{4}, Page = nextPage }})", tbl.Name, fk.ReferTo, fk.Name, fk.ReferTo.Pluralize(), referTbl.GetPrimaryKey().Name));
            }
            else
            {
                contents.Append(string.Format("@Html.ActionLink(\" \", \"Select{0}\", new {{ Page = nextPage }})",
                                              tbl.Name));
            }

            return contents.ToString();
        }
    }
}
